<template>
  <base-option :selected="selected" :field-config="fieldConfig" :form-config="formConfig">
    <template #default="{ hideOptions }">
      <el-form-item v-if="fieldConfig.defaultValue !== undefined && hideOptions('defaultValue')" label="默认值">
        <el-select v-model="fieldConfig.defaultValueType" placeholder="">
          <el-option label="自定义" :value="0" />
          <el-option label="公式编辑" :value="1" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="fieldConfig.defaultValueType === 0">
        <el-input
          v-model="fieldConfig.defaultValue"
          type="textarea"
          :rows="2"
          :maxlength="fieldConfig.maxlength"
          placeholder="请输入默认值"
          show-word-limit
        />
      </el-form-item>
      <el-form-item v-if="fieldConfig.defaultValueType === 1">
        <el-button style="flex: 1" plain @click="dialogCode = true">编辑公式</el-button>
      </el-form-item>

      <el-form-item v-if="fieldConfig.append !== undefined && hideOptions('append')" label="后置内容">
        <el-input v-model="fieldConfig.append" maxlength="3" placeholder="请输入后置显示文字" />
      </el-form-item>

      <el-form-item v-if="fieldConfig.maxlength !== undefined && hideOptions('maxlength')" label="长度限制">
        <el-input
          v-model="fieldConfig.maxlength"
          type="number"
          min="1"
          max="20"
          placeholder="最大字符长度"
          @blur="limitInput"
        />
      </el-form-item>

      <el-form-item v-if="fieldConfig.showWordLimit !== undefined && hideOptions('showWordLimit')" label="显示计数器">
        <el-switch v-model="fieldConfig.showWordLimit" size="default" />
      </el-form-item>
    </template>
  </base-option>
  <el-dialog
    v-model="dialogCode"
    title="公式编辑"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    destroy-on-close
  >
    <el-card shadow="never">
      <code-editor-formula ref="editorRef" v-model="formulaCode" />
    </el-card>

    <el-row :gutter="20" style="margin-top: 20px; height: 230px">
      <el-col :span="7">
        <el-card shadow="never" :body-style="{ 'padding-right': '0px' }">
          <template #header>
            <div class="card-header">
              <span style="font-size: 12px">当前表单字段与公共变量</span>
            </div>
          </template>
          <el-scrollbar height="170px">
            <ul style="color: #606266; line-height: 2; padding-right: 12px">
              <li
                v-for="(item, i) in formFields"
                :key="i"
                style="display: flex; justify-content: space-between; align-items: center"
              >
                <el-link underline="never" style="font-size: 12px" @click="handleInsertVar(item)">{{
                  item.label
                }}</el-link>
                <el-tag v-if="item.label.includes('DATA.')" type="primary" size="small">{{ item.type }}</el-tag>
                <el-tag v-else type="warning" size="small">{{ item.type }}</el-tag>
              </li>
            </ul>
          </el-scrollbar>
        </el-card>
      </el-col>
      <el-col :span="6">
        <el-card shadow="never" :body-style="{ padding: '0px' }">
          <template #header>
            <div class="card-header">
              <span style="font-size: 12px">函数列表</span>
            </div>
          </template>
          <el-scrollbar height="170px">
            <el-tree :data="functionsList" accordion @node-click="handleNodeClick" @node-collapse="handleNodeCollapse">
              <template #default="{ node, data }">
                <div
                  style="font-size: 12px; flex: 1; display: flex; justify-content: space-between; align-items: center"
                  :style="{ margin: data.value ? '0 12px 0 -18px' : '' }"
                  @mouseover="handleNodeMouseover(data)"
                >
                  <span>{{ data.value || node.label }}</span>
                  <el-tag v-if="data.type" :type="data.type">{{ node.label }}</el-tag>
                </div>
              </template>
            </el-tree>
          </el-scrollbar>
        </el-card>
      </el-col>
      <el-col :span="11">
        <el-card shadow="never" style="color: #606266; line-height: 2; font-size: 12px">
          <el-scrollbar height="210px">
            <div v-if="tipRedmer" v-html="tipRedmer" />
            <div v-else style="display: flex; flex-wrap: wrap">
              <ul style="list-style: disc; padding-left: 20px">
                <li>请从左侧面板选择字段名和函数，或输入函数</li>
                <li>支持50+常用Excel函数，支持多层嵌套函数调用</li>
                <li>配合自定义组件使用，支持公共变量</li>
                <li>简单公式计算：SUM({基本工资}, {加班工资})</li>
              </ul>
              <el-link
                v-if="showFastCodeLinks.includes(0)"
                type="primary"
                underline="never"
                style="padding-left: 20px; font-size: 12px"
                @click="onFastCode(0)"
              >
                [请假组件-退餐统计]
              </el-link>
            </div>
          </el-scrollbar>
        </el-card>
      </el-col>
    </el-row>

    <template #footer>
      <span class="dialog-footer">
        <el-button type="primary" @click="handleSave">确定</el-button>
        <el-button @click="dialogCode = false">关闭</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup>
import _ from 'lodash'
import { ref, toRefs, computed, watch } from 'vue'
import baseOption from './base-option.vue'
import propsDefinition from './props'
import { ExcelFields, FastCodes, FastPublicVars, strTofunc } from '../../widget-form/field/excelFormulaParser'

const props = defineProps(propsDefinition)
const { selected, fieldConfig, formConfig, widgetList } = toRefs(props)

const editorRef = ref(null)
const dialogCode = ref(false)
const formulaCode = ref('')
const formulaVars = ref(null)
const selectedFunKey = ref(null)
const tipRedmer = computed(() => functions[selectedFunKey.value] || '')

// 函数分类列表
const functionsList = ref([
  {
    label: '逻辑函数',
    children: [
      {
        label: '布尔',
        value: 'IF',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'AND',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'OR',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'NOT',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'XOR',
        type: 'warning'
      }
    ]
  },
  {
    label: '比较函数',
    children: [
      {
        label: '布尔',
        value: 'EQ',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'NE',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'GT',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'GE',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'LT',
        type: 'warning'
      },
      {
        label: '布尔',
        value: 'LE',
        type: 'warning'
      }
    ]
  },
  {
    label: '数学函数',
    children: [
      {
        label: '数字',
        value: 'ADD',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'SUB',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'MUL',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'DIV',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'MOD',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'POW',
        type: 'primary'
      }
    ]
  },
  {
    label: '循环函数',
    children: [
      {
        label: '数字',
        value: 'SUM',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'PRODUCT',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'COUNT',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'AVERAGE',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'MIN',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'MAX',
        type: 'primary'
      }
    ]
  },
  {
    label: '日期函数',
    children: [
      {
        label: '日期',
        value: 'DATE',
        type: 'success'
      },
      {
        label: '数字',
        value: 'DATEDIFF',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'DAY',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'MONTH',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'YEAR',
        type: 'primary'
      }
    ]
  },
  {
    label: '文本函数',
    children: [
      {
        label: '文本',
        value: 'CONCAT',
        type: 'warning'
      },
      {
        label: '数字',
        value: 'LEN',
        type: 'primary'
      },
      {
        label: '文本',
        value: 'LEFT',
        type: 'warning'
      },
      {
        label: '文本',
        value: 'RIGHT',
        type: 'warning'
      }
    ]
  },
  {
    label: '数组函数',
    children: [
      {
        label: '数组',
        value: 'MAP',
        type: 'danger'
      },
      {
        label: '数组',
        value: 'FILTER',
        type: 'danger'
      },
      {
        label: '数字',
        value: 'REDUCE',
        type: 'primary'
      },
      {
        label: '数字',
        value: 'ARRAY',
        type: 'primary'
      }
    ]
  }
])
// 函数说明
const functions = {
  IF: `<font color="#930f80">IF</font>函数用于条件判断，如果满足条件则返回一个值，如果不满足，则返回另外一个值。<br>
  语法：<font color="#930f80">IF</font>(逻辑测试, 值如果为真, 值如果为假)<br>
  例如：<font color="#930f80">IF</font>(A1>10, "大于10", "小于等于10")<br>
  其中A1是要测试的条件，如果A1的值大于10，则返回"大于10"，否则返回"小于等于10"。<br>
  也可以嵌套使用多个<font color="#930f80">IF</font>函数来处理更复杂的条件判断。
`,
  AND: `<font color="#930f80">AND</font>函数用于判断多个条件是否同时满足，如果所有条件都为真，则返回真，否则返回假。<br>
  语法：<font color="#930f80">AND</font>(逻辑1, [逻辑2], ...)<br>
  例如：<font color="#930f80">AND</font>(A1>10, B1<20)<br>
  其中A1和B1是要测试的条件，如果A1大于10且B1小于20，则返回真，否则返回假。<br>
  <font color="#930f80">AND</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  OR: `<font color="#930f80">OR</font>函数用于判断多个条件中是否至少有一个满足，如果至少有一个条件为真，则返回真，否则返回假。<br>
  语法：<font color="#930f80">OR</font>(逻辑1, [逻辑2], ...)<br>
  例如：<font color="#930f80">OR</font>(A1>10, B1<20)<br>
  其中A1和B1是要测试的条件，如果A1大于10或B1小于20，则返回真，否则返回假。<br>
  <font color="#930f80">OR</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  NOT: `<font color="#930f80">NOT</font>函数用于对逻辑值取反，如果逻辑值为真，则返回假；如果逻辑值为假，则返回真。<br>
  语法：<font color="#930f80">NOT</font>(逻辑)<br>
  例如：<font color="#930f80">NOT</font>(A1>10)<br>
  其中A1是要测试的条件，如果A1大于10，则<font color="#930f80">NOT</font>函数返回假，否则返回真。<br>
  <font color="#930f80">NOT</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  XOR: `<font color="#930f80">XOR</font>函数用于判断多个条件中是否有奇数个条件为真，如果奇数个条件为真，则返回真，否则返回假。<br>
  语法：<font color="#930f80">XOR</font>(逻辑1, [逻辑2], ...)<br>
  例如：<font color="#930f80">XOR</font>(A1>10, B1<20)<br>
  其中A1和B1是要测试的条件，如果A1大于10且B1小于20的条件为奇数个，则返回真，否则返回假。<br>
  <font color="#930f80">XOR</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  EQ: `<font color="#930f80">EQ</font>函数用于判断两个值是否相等，如果相等则返回真，否则返回假。<br>
  语法：<font color="#930f80">EQ</font>(值1, 值2)<br>
  例如：<font color="#930f80">EQ</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1等于B1，则返回真，否则返回假。<br>
  <font color="#930f80">EQ</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  NE: `<font color="#930f80">NE</font>函数用于判断两个值是否不相等，如果不相等则返回真，否则返回假。<br>
  语法：<font color="#930f80">NE</font>(值1, 值2)<br>
  例如：<font color="#930f80">NE</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1不等于B1，则返回真，否则返回假。<br>
  <font color="#930f80">NE</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  GT: `<font color="#930f80">GT</font>函数用于判断第一个值是否大于第二个值，如果大于则返回真，否则返回假。<br>
  语法：<font color="#930f80">GT</font>(值1, 值2)<br>
  例如：<font color="#930f80">GT</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1大于B1，则返回真，否则返回假。<br>
  <font color="#930f80">GT</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  GE: `<font color="#930f80">GE</font>函数用于判断第一个值是否大于或等于第二个值，如果大于或等于则返回真，否则返回假。<br>
  语法：<font color="#930f80">GE</font>(值1, 值2)<br>
  例如：<font color="#930f80">GE</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1大于或等于B1，则返回真，否则返回假。<br>
  <font color="#930f80">GE</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  LT: `<font color="#930f80">LT</font>函数用于判断第一个值是否小于第二个值，如果小于则返回真，否则返回假。<br>
  语法：<font color="#930f80">LT</font>(值1, 值2)<br>
  例如：<font color="#930f80">LT</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1小于B1，则返回真，否则返回假。<br>
  <font color="#930f80">LT</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  LE: `<font color="#930f80">LE</font>函数用于判断第一个值是否小于或等于第二个值，如果小于或等于则返回真，否则返回假。<br>
  语法：<font color="#930f80">LE</font>(值1, 值2)<br>
  例如：<font color="#930f80">LE</font>(A1, B1)<br>
  其中A1和B1是要比较的值，如果A1小于或等于B1，则返回真，否则返回假。<br>
  <font color="#930f80">LE</font>函数可以与<font color="#930f80">IF</font>函数结合使用来进行更复杂的条件判断。`,
  ADD: `<font color="#930f80">ADD</font>函数用于对两个数值进行加法运算。<br>
  语法：<font color="#930f80">ADD</font>(数字1, 数字2)<br>
  例如：<font color="#930f80">ADD</font>(10, 20) 返回 30<br>
  其中数字1和数字2是要相加的数值。<br>`,
  SUB: `<font color="#930f80">SUB</font>函数用于对两个数值进行减法运算。<br>
  语法：<font color="#930f80">SUB</font>(数字1, 数字2)<br>
  例如：<font color="#930f80">SUB</font>(20, 10) 返回 10<br>
  其中数字1是被减数，数字2是减数。<br>`,
  MUL: `<font color="#930f80">MUL</font>函数用于对两个数值进行乘法运算。<br>
  语法：<font color="#930f80">MUL</font>(数字1, 数字2)<br>
  例如：<font color="#930f80">MUL</font>(10, 20) 返回 200<br>
  其中数字1和数字2是要相乘的数值。<br>`,
  DIV: `<font color="#930f80">DIV</font>函数用于对两个数值进行除法运算。<br>
  语法：<font color="#930f80">DIV</font>(数字1, 数字2)<br>
  例如：<font color="#930f80">DIV</font>(20, 10) 返回 2<br>
  其中数字1是被除数，数字2是除数。<br>`,
  MOD: `<font color="#930f80">MOD</font>函数用于对两个数值进行取模运算。<br>
  语法：<font color="#930f80">MOD</font>(数字1, 数字2)<br>
  例如：<font color="#930f80">MOD</font>(20, 3) 返回 2<br>
  其中数字1是被除数，数字2是除数。<br>`,
  POW: `<font color="#930f80">POW</font>函数用于对一个数值进行幂运算。<br>
  语法：<font color="#930f80">POW</font>(数字, 指数)<br>
  例如：<font color="#930f80">POW</font>(2, 3) 返回 8<br>
  其中数字是底数，指数是幂的指数。<br>`,
  SUM: `<font color="#930f80">SUM</font>函数可以对一组数值进行求和<br>
  语法：<font color="#930f80">SUM</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">SUM</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要相加的数值。<br>
  例如：<font color="#930f80">SUM</font>(10, 20, 30) 返回 60<br>`,
  PRODUCT: `<font color="#930f80">PRODUCT</font>函数可以对一组数值进行乘积计算<br>
  语法：<font color="#930f80">PRODUCT</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">PRODUCT</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要相乘的数值。<br>
  例如：<font color="#930f80">PRODUCT</font>(2, 3, 4) 返回 24<br>`,
  COUNT: `<font color="#930f80">COUNT</font>函数可以计算一组数值中的非空单元格数量<br>
  语法：<font color="#930f80">COUNT</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">COUNT</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要计算的数值。<br>
  例如：<font color="#930f80">COUNT</font>(10, 20, 30) 返回 3<br>`,
  AVERAGE: `<font color="#930f80">AVERAGE</font>函数可以获取一组数值的算术平均值<br>
  语法：<font color="#930f80">AVERAGE</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">AVERAGE</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要计算平均值的数值。<br>
  例如：<font color="#930f80">AVERAGE</font>(10, 20, 30) 返回 20<br
  `,
  MIN: `<font color="#930f80">MIN</font>函数可以获取一组数值中的最小值<br>
  语法：<font color="#930f80">MIN</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">MIN</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要计算最小值的数值。<br>
  例如：<font color="#930f80">MIN</font>(10, 20, 30) 返回 10<br>
  `,
  MAX: `<font color="#930f80">MAX</font>函数可以获取一组数值中的最大值<br>
  语法：<font color="#930f80">MAX</font>(数字1, 数字2, ...) 或<br>
  <font color="#930f80">MAX</font>([数字1, 数字2, ...]) <br>
  其中数字1, 数字2, ... 是要计算最大值的数值。<br>
  例如：<font color="#930f80">MAX</font>(10, 20, 30) 返回 30<br>
  `,
  DATE: `<font color="#930f80">DATE</font>函数用于创建一个日期值。<br>
  语法：<font color="#930f80">DATE</font>(年, 月, 日)<br>
  例如：<font color="#930f80">DATE</font>(2023, 10, 1) 返回 2023年10月1日的日期值。<br>
  其中年、月、日分别表示年份、月份和日期。<br>`,
  DATEDIFF: `<font color="#930f80">DATEDIFF</font>函数用于计算两个日期之间的差值。<br>
  语法：<font color="#930f80">DATEDIFF</font>(日期1, 日期2)<br>
  例如：<font color="#930f80">DATEDIFF</font>(DATE(2023, 10, 1), DATE(2023, 9, 1)) 返回 30，表示两个日期之间相差30天。<br>
  其中日期1和日期2分别表示要计算差值的两个日期。<br>`,
  DAY: `<font color="#930f80">DAY</font>函数用于获取日期中的天数部分。<br>
  语法：<font color="#930f80">DAY</font>(日期)<br>
  例如：<font color="#930f80">DAY</font>(DATE(2023, 10, 1)) 返回 1，表示2023年10月1日的天数部分。<br>
  其中日期表示要获取天数的日期值。<br>`,
  MONTH: `<font color="#930f80">MONTH</font>函数用于获取日期中的月份部分。<br>
  语法：<font color="#930f80">MONTH</font>(日期)<br>
  例如：<font color="#930f80">MONTH</font>(DATE(2023, 10, 1)) 返回 10，表示2023年10月的月份部分。<br>
  其中日期表示要获取月份的日期值。<br>`,
  YEAR: `<font color="#930f80">YEAR</font>函数用于获取日期中的年份部分。<br>
  语法：<font color="#930f80">YEAR</font>(日期)<br>
  例如：<font color="#930f80">YEAR</font>(DATE(2023, 10, 1)) 返回 2023，表示2023年的年份部分。<br>
  其中日期表示要获取年份的日期值。<br>`,
  CONCAT: `<font color="#930f80">CONCAT</font>函数用于连接多个文本字符串。<br>
  语法：<font color="#930f80">CONCAT</font>(文本1, 文本2, ...) 或<br>
  <font color="#930f80">CONCAT</font>([文本1, 文本2, ...]) <br>
  例如：<font color="#930f80">CONCAT</font>("Hello", " ", "World") 返回 "Hello World"<br>
  其中文本1, 文本2, ... 是要连接的文本字符串。<br>`,
  LEN: `<font color="#930f80">LEN</font>函数用于获取文本字符串的长度。<br>
  语法：<font color="#930f80">LEN</font>(文本)<br>
  例如：<font color="#930f80">LEN</font>("Hello World") 返回 11，表示字符串 "Hello World" 的长度为11个字符。<br>
  其中文本表示要获取长度的文本字符串。<br>`,
  LEFT: `<font color="#930f80">LEFT</font>函数用于获取文本字符串的左侧指定数量的字符。<br>
  语法：<font color="#930f80">LEFT</font>(文本, num_chars)<br>
  例如：<font color="#930f80">LEFT</font>("Hello World", 5) 返回 "Hello"，表示获取字符串 "Hello World" 的左侧5个字符。<br>
  其中文本表示要处理的文本字符串，num_chars表示要获取的字符数量。<br>`,
  RIGHT: `<font color="#930f80">RIGHT</font>函数用于获取文本字符串的右侧指定数量的字符。<br>
  语法：<font color="#930f80">RIGHT</font>(文本, num_chars)<br>
  例如：<font color="#930f80">RIGHT</font>("Hello World", 5) 返回 "World"，表示获取字符串 "Hello World" 的右侧5个字符。<br>
  其中文本表示要处理的文本字符串，num_chars表示要获取的字符数量。<br>`,
  MAP: `<font color="#930f80">MAP</font>函数用于对数组中的每个元素应用一个函数，并返回一个新的数组。<br>
  语法：<font color="#930f80">MAP</font>(array, lambda)<br>
  例如：<font color="#930f80">MAP</font>([1, 2, 3], x => x * 2) 返回 [2, 4, 6]，表示对数组中的每个元素乘以2。<br>
  其中array是要处理的数组，lambda是应用于每个元素的函数。<br>`,
  FILTER: `<font color="#930f80">FILTER</font>函数用于从数组中筛选出满足条件的元素，并返回一个新的数组。<br>
  语法：<font color="#930f80">FILTER</font>(array, lambda)<br>
  例如：<font color="#930f80">FILTER</font>([1, 2, 3, 4], x => x > 2) 返回 [3, 4]，表示筛选出大于2的元素。<br>
  其中array是要处理的数组，lambda是筛选条件函数。<br>`,
  REDUCE: `<font color="#930f80">REDUCE</font>函数用于对数组中的元素进行累积计算，并返回一个单一的值。<br>
  语法：<font color="#930f80">REDUCE</font>(array, lambda, initialValue)<br>
  例如：<font color="#930f80">REDUCE</font>([1, 2, 3], (acc, x) => acc + x, 0) 返回 6，表示对数组中的元素进行求和。<br>
  其中array是要处理的数组，lambda是累积计算函数，initialValue是初始值。<br>`,
  ARRAY: `<font color="#930f80">ARRAY</font>函数用于创建一个数组。<br>
  语法：<font color="#930f80">ARRAY</font>(元素1, 元素2, ...) 或<br>
  <font color="#930f80">ARRAY</font>([元素1, 元素2, ...]) <br>
  例如：<font color="#930f80">ARRAY</font>(1, 2, 3) 返回 [1, 2, 3]，表示创建一个包含1、2、3的数组。<br>
  其中元素1, 元素2, ... 是要包含在数组中的元素。<br>`
}

const handleNodeMouseover = (data) => {
  const { value } = data
  if (value) {
    selectedFunKey.value = value
  }
}

const handleNodeClick = (data) => {
  const { value } = data
  if (value) {
    editorRef.value.insertValue(value + '()')
    editorRef.value.focus(-1)
  } else {
    selectedFunKey.value = null
  }
}

const handleNodeCollapse = () => {
  selectedFunKey.value = null
}

function objToList(obj) {
  return Object.entries(obj).map(([key, value]) => {
    let type = 'Object'
    if (typeof value === 'number') {
      type = 'Number'
    }
    if (typeof value === 'string') {
      type = 'String'
    }
    if (typeof value === 'function') {
      type = 'Function'
    }
    if (Array.isArray(value)) {
      type = 'Array'
      try {
        value = JSON.stringify(value)
      } catch (e) {
        // 如果转换失败，保留原始值
      }
    }
    return {
      label: key,
      value: String(value),
      type: type
    }
  })
}

// 表单内字段和全局变量列表，必须使用自定义组件内表单和全局变量，并且排除自身文本框
const formFields = computed(() => {
  const arr = widgetList.value
    .filter((x) => ExcelFields.includes(x.type) && x.id !== selected.value.id)
    .map((x) => {
      return {
        label: 'DATA.' + x.options.label,
        value: '表单组件',
        type: x.name
      }
    })
  const config = widgetList.value.find((x) => x.type === 'card')
  if (config && Array.isArray(config.components)) {
    const names = config.components
      .filter((x) => ExcelFields.includes(x.type) && x.id !== selected.value.id)
      .map((x) => {
        return {
          label: 'DATA.' + x.options.label,
          value: '表单组件',
          type: x.name
        }
      })
    arr.push(...names)
  }
  if (config && typeof config.options.publicVars === 'object') {
    const copypublicVars = JSON.parse(JSON.stringify(config.options.publicVars))
    strTofunc(copypublicVars)
    arr.push(...objToList(copypublicVars))
  }

  // 临时使用变量
  if (formulaVars.value) {
    const copyformulaVars = JSON.parse(JSON.stringify(formulaVars.value))
    strTofunc(copyformulaVars)
    arr.push(...objToList(copyformulaVars))
  }
  return arr
})

// 保存编辑公式
const handleSave = () => {
  fieldConfig.value.defaultValue = ''
  fieldConfig.value.defaultValueFunc = formulaCode.value
  const config = widgetList.value.find((x) => x.type === 'card')
  if (config && config.options.publicVars) {
    _.merge(config.options.publicVars, formulaVars.value || {})
  }
  dialogCode.value = false
}

// 插入变量
const handleInsertVar = (item) => {
  if (item.type === 'Function') {
    // 使用正则表达式匹配括号内的参数列表
    const paramsMatch = item.value.match(/\(([^)]*)\)/)
    // 提取完整参数列表（包含括号）
    const paramsString = paramsMatch ? paramsMatch[0] : '()'
    editorRef.value.insertValue('{' + item.label + '}' + paramsString)
    editorRef.value.focus()
  } else {
    editorRef.value.insertValue('{' + item.label + '}')
    editorRef.value.focus()
  }
}

// 检查表单中自定义组件，显示对于的快速公式按钮
const showFastCodeLinks = computed(() => {
  const links = []
  if (widgetList.value.find((x) => x.type === 'card' && x.options.name === 'leave')) {
    links.push(0)
  }
  return links
})

// 使用快速公式
const onFastCode = (n) => {
  editorRef.value.setValue(FastCodes[n])
  formulaVars.value = FastPublicVars[n]
}

watch(dialogCode, (val) => {
  if (val) {
    selectedFunKey.value = null
    formulaCode.value = fieldConfig.value.defaultValueFunc || ''
    formulaVars.value = null
  }
})

const limitInput = () => {
  if (fieldConfig.value.maxlength > 20) {
    fieldConfig.value.maxlength = '20'
  }
  if (fieldConfig.value.maxlength < 1) {
    fieldConfig.value.maxlength = '1'
  }
}
</script>
